/*
 * Unidata Platform
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 *
 * Commercial License
 * This version of Unidata Platform is licensed commercially and is the appropriate option for the vast majority of use cases.
 *
 * Please see the Unidata Licensing page at: https://unidata-platform.com/license/
 * For clarification or additional options, please contact: info@unidata-platform.com
 * -------
 * Disclaimer:
 * -------
 * THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND
 * REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 * IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, NON-INFRINGEMENT, PERFORMANCE AND
 * THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING.
 */
package org.unidata.mdm.rest.v1.search.ro;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.commons.collections4.CollectionUtils;

/**
 * @author Dmitrii Kopin
 * REST search form fields group.
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public class SearchFormFieldsGroupRO {
    /**
     * Collection of form fields
     */
    @Nonnull
    private Collection<SearchFormFieldRO> formFields;

    private List<SearchFormFieldsGroupRO> childGroups;

    /**
     * Type of group
     */
    @Nonnull
    private GroupType groupType;


    public SearchFormFieldsGroupRO() {
    }
    /**
     * Constructor
     *
     * @param joinType
     * @param formFields
     */
    public SearchFormFieldsGroupRO(@Nonnull GroupType joinType, @Nonnull Collection<SearchFormFieldRO> formFields) {
        this.groupType = joinType;
        this.formFields = formFields;
    }

    /**
     * Create group form field which will be compose over logical 'AND'
     *
     * @param formField - logical group of form fields for searching.
     * @return AND group
     */
    @Nonnull
    public static SearchFormFieldsGroupRO createAndGroup(@Nonnull SearchFormFieldRO... formField) {
        Collection<SearchFormFieldRO> fieldList = Arrays.stream(formField)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        return new SearchFormFieldsGroupRO(GroupType.AND, fieldList);
    }

    /**
     * Create group form field which will be compose over logical 'AND'
     *
     * @param formFields - logical group of form fields for searching.
     * @return AND group
     */
    @Nonnull
    public static SearchFormFieldsGroupRO createAndGroup(@Nonnull Collection<SearchFormFieldRO> formFields) {
        Collection<SearchFormFieldRO> fieldList = formFields.stream().filter(Objects::nonNull).collect(Collectors.toList());
        return new SearchFormFieldsGroupRO(GroupType.AND, fieldList);
    }

    /**
     * Create group form field which will be compose over logical 'AND'
     *
     * @return AND group
     */
    @Nonnull
    public static SearchFormFieldsGroupRO createAndGroup() {
        return new SearchFormFieldsGroupRO(GroupType.AND, new ArrayList<>());
    }

    /**
     * Create group form fields which will be compose over logical 'OR'
     *
     * @param formFields - logical group of form fields for searching.
     */
    public static SearchFormFieldsGroupRO createOrGroup(@Nonnull Collection<SearchFormFieldRO> formFields) {
        Collection<SearchFormFieldRO> fieldList = formFields.stream().filter(Objects::nonNull).collect(Collectors.toList());
        return new SearchFormFieldsGroupRO(GroupType.OR, fieldList);
    }

    /**
     * @return empty OR group
     */
    public static SearchFormFieldsGroupRO createOrGroup() {
        return new SearchFormFieldsGroupRO(GroupType.OR, new ArrayList<>());
    }

    /**
     * @param formField - form field
     * @return - self
     */
    public SearchFormFieldsGroupRO addFormField(SearchFormFieldRO formField) {
        if (formField != null) {
            formFields.add(formField);
        }
        return this;
    }

    public SearchFormFieldsGroupRO addChildGroup(SearchFormFieldsGroupRO childGroup) {
        if (childGroups == null) {
            childGroups = new ArrayList<>();
        }
        childGroups.add(childGroup);
        return this;
    }

    /**
     * @return true if group is empty
     */
    public boolean isEmpty() {
        return CollectionUtils.isEmpty(formFields) && CollectionUtils.isEmpty(childGroups);
    }

    @Nonnull
    public Collection<SearchFormFieldRO> getFormFields() {
        return Collections.unmodifiableCollection(formFields);
    }

    @Nonnull
    public GroupType getGroupType() {
        return groupType;
    }

    public List<SearchFormFieldsGroupRO> getChildGroups() {
        return childGroups;
    }

    public enum GroupType {
        OR, AND;
    }
}
